package com.edfeff.nio.http;

import com.edfeff.bio.http.Constants;
import com.edfeff.bio.http.Header;
import com.edfeff.bio.http.Request;
import com.edfeff.bio.http.StrUtils;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class NioInputBuffer {
    private SocketChannel socket;
    private Request request;
    private ByteBuffer readBuffer;
    private byte[] buf;
    protected int pos;
    protected int lastValid;


    public NioInputBuffer(Request request, SocketChannel socket) {
        this.request = request;
        this.socket = socket;
        this.readBuffer = ByteBuffer.allocate(8192);
        this.buf = new byte[8192];
        this.pos = 0;
        this.lastValid = 0;
    }

    public void parseRequestLine() {
        //1 Method SP 读取方法名字
        StringBuilder charTemp = new StringBuilder();
        boolean space = false;
        while (!space) {
            //填充buf
            fill();
            if (buf[pos] == Constants.SP) {
                space = true;
                request.setMethod(charTemp.toString());
            } else {
                charTemp.append((char) buf[pos]);
            }
            pos++;
        }

        //2 Request-URI SP 读取uri
        int start = pos;
        space = false;
        int end = 0;
        while (!space) {
            fill();
            if (buf[pos] == Constants.SP) {
                space = true;
                end = pos;
            }
            pos++;
        }
        request.setUri(StrUtils.from(buf, start, end - start));

        //3. HTTP-Version CRLF 读取版本
        // http/1.1 CR LF
        // ↑        ↑   ↑
        //start    end endOfLine
        charTemp = new StringBuilder();
        boolean endOfLine = false;
        while (!endOfLine) {
            fill();
            if (buf[pos] == Constants.CR) {
                //nothing
            } else if (buf[pos] == Constants.LF) {
                //标记请求行结束
                endOfLine = true;
            } else {
                //只添加非空白字符
                charTemp.append((char) buf[pos]);
            }
            pos++;
        }
        request.setProtocol(charTemp.toString());
    }


    public void parseHeaders() throws IOException {
        while (parseHeader()) ;
    }

    private boolean parseHeader() throws IOException {
        //空白符号跳过 和 头部结束判断
        byte chr = 0;
        while (true) {
            fill();
            chr = buf[pos];
            if ((chr == Constants.CR) || (chr == Constants.LF)) {
                if (chr == Constants.LF) {
                    pos++;
                    return false;
                }
            } else {
                break;
            }
            pos++;
        }

        //格式 headerName : SP headerValues
        Header header = new Header();
        //1 解析键
        StringBuilder headerTmp = new StringBuilder();
        //分号标记，区分请求头的键和值
        boolean colon = false;
        while (!colon) {
            // Read new bytes if needed
            fill();
            if (buf[pos] == Constants.COLON) {
                colon = true;
                header.setName(headerTmp.toString());
            } else {
                headerTmp.append(Character.toLowerCase((char) buf[pos]));
            }
            pos++;
        }

        //2 解析值
        // 跳过空白符号 空格、制表符
        boolean space = true;
        while (space) {
            fill();
            if ((buf[pos] == Constants.SP) || (buf[pos] == Constants.HT)) {
                pos++;
            } else {
                space = false;
            }
        }

        // 读取数据到行结束CRLF
        int start = pos;
        int end = 0;
        boolean endOfLine = false;
        headerTmp = new StringBuilder();

        while (!endOfLine) {
            fill();
            if (buf[pos] == Constants.CR) {
                end = pos;
            } else if (buf[pos] == Constants.LF) {
                endOfLine = true;
            }
            pos++;
        }
        headerTmp.append(StrUtils.from(buf, start, end - start));
        header.setValue(headerTmp.toString());
        request.getHeaders().add(header);
        return true;
    }


    private void fill() {
        try {
            if (pos >= lastValid) {
                readBuffer.clear();
                int n = socket.read(readBuffer);
                readBuffer.flip();
                readBuffer.limit(n);
                readBuffer.get(buf, pos, n);
                lastValid = pos + n;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void parseRequestBody() {
        //请求体长度
        long contentLength = request.getContentLengthLong();
        if (contentLength <= 0)
            return;
        //读取请求体 包装到byte[]中
        fill();
        int len = (int) contentLength;
        byte[] body = new byte[len];
        System.arraycopy(buf, pos, body, 0, len);
        request.setBody(body);
    }
}
